`timescale 1ns/1ps
`default_nettype none

module cxy_pixel_display_buf_offset
    #(
    parameter   DW          = 96
    )
    (
    // config
    input  wire [9:0]       I_cfg_pt_offset_0 ,
    input  wire [9:0]       I_cfg_pt_offset_1 ,
    input  wire [9:0]       I_cfg_pt_offset_2 ,
    input  wire [9:0]       I_cfg_pt_offset_3 ,
    input  wire [9:0]       I_cfg_pt_offset_4 ,
    input  wire [9:0]       I_cfg_pt_offset_5 ,
    input  wire [9:0]       I_cfg_pt_offset_6 ,
    input  wire [9:0]       I_cfg_pt_offset_7 ,
    input  wire [9:0]       I_cfg_pt_offset_8 ,
    input  wire [9:0]       I_cfg_pt_offset_9 ,
    input  wire [9:0]       I_cfg_pt_offset_10,
    input  wire [9:0]       I_cfg_pt_offset_11,
    input  wire [9:0]       I_cfg_pt_offset_12,
    input  wire [9:0]       I_cfg_pt_offset_13,
    input  wire [9:0]       I_cfg_pt_offset_14,
    input  wire [9:0]       I_cfg_pt_offset_15,
    input  wire [9:0]       I_cfg_pt_offset_16,
    input  wire [9:0]       I_cfg_pt_offset_17,
    input  wire [9:0]       I_cfg_pt_offset_18,
    input  wire [9:0]       I_cfg_pt_offset_19,
    input  wire [9:0]       I_cfg_pt_offset_20,
    input  wire [9:0]       I_cfg_pt_offset_21,
    input  wire [9:0]       I_cfg_pt_offset_22,
    input  wire [9:0]       I_cfg_pt_offset_23,
    input  wire [9:0]       I_cfg_pt_offset_24,
    input  wire [9:0]       I_cfg_pt_offset_25,
    input  wire [9:0]       I_cfg_pt_offset_26,
    input  wire [9:0]       I_cfg_pt_offset_27,
    input  wire [9:0]       I_cfg_pt_offset_28,
    input  wire [9:0]       I_cfg_pt_offset_29,
    input  wire [9:0]       I_cfg_pt_offset_30,
    input  wire [9:0]       I_cfg_pt_offset_31,
    // write
    input  wire             I_wclk,
    input  wire [7:0]       I_wren,
    input  wire [8:0]       I_waddr,
    input  wire [23:0]      I_wdata,
    // read
    input  wire             I_rclk,
    input  wire             I_rden,
    input  wire [9:0]       I_raddr,
    output wire [DW-1:0]    O_rdata
    );
//***********************************************************
localparam  M = DW/12;

wire            rd_clk;
wire            rd_en;
wire [23:0]     q;

reg  [8:0]      ad_0 ;
reg  [8:0]      ad_1 ;
reg  [8:0]      ad_2 ;
reg  [8:0]      ad_3 ;
reg  [8:0]      ad_4 ;
reg  [8:0]      ad_5 ;
reg  [8:0]      ad_6 ;
reg  [8:0]      ad_7 ;
reg  [8:0]      ad_8 ;
reg  [8:0]      ad_9 ;
reg  [8:0]      ad_10;
reg  [8:0]      ad_11;
reg  [8:0]      ad_12;
reg  [8:0]      ad_13;
reg  [8:0]      ad_14;
reg  [8:0]      ad_15;
reg  [8:0]      ad_16;
reg  [8:0]      ad_17;
reg  [8:0]      ad_18;
reg  [8:0]      ad_19;
reg  [8:0]      ad_20;
reg  [8:0]      ad_21;
reg  [8:0]      ad_22;
reg  [8:0]      ad_23;
reg  [8:0]      ad_24;
reg  [8:0]      ad_25;
reg  [8:0]      ad_26;
reg  [8:0]      ad_27;
reg  [8:0]      ad_28;
reg  [8:0]      ad_29;
reg  [8:0]      ad_30;
reg  [8:0]      ad_31;

reg  [11:0]     rd_addr_0;
reg  [11:0]     rd_addr_1;
reg  [11:0]     rd_addr_2;
reg  [11:0]     rd_addr_3;
reg  [11:0]     rd_addr_4;
reg  [11:0]     rd_addr_5;
reg  [11:0]     rd_addr_6;
reg  [11:0]     rd_addr_7;

reg  [4:0]      rden_sr;
reg  [2:0]      rd_turn;
reg  [DW-1:0]   q_tmp;
//***********************************************************
//-------------------------------------
// instance of dpram_512x24_4096x3
//-------------------------------------
dpram_512x24_4096x3 buf0 (.wrclock(I_wclk),.wren(I_wren[0]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_0),.q(q[2 :0 ]));
dpram_512x24_4096x3 buf1 (.wrclock(I_wclk),.wren(I_wren[1]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_1),.q(q[5 :3 ]));
dpram_512x24_4096x3 buf2 (.wrclock(I_wclk),.wren(I_wren[2]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_2),.q(q[8 :6 ]));
dpram_512x24_4096x3 buf3 (.wrclock(I_wclk),.wren(I_wren[3]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_3),.q(q[11:9 ]));
dpram_512x24_4096x3 buf4 (.wrclock(I_wclk),.wren(I_wren[4]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_4),.q(q[14:12]));
dpram_512x24_4096x3 buf5 (.wrclock(I_wclk),.wren(I_wren[5]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_5),.q(q[17:15]));
dpram_512x24_4096x3 buf6 (.wrclock(I_wclk),.wren(I_wren[6]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_6),.q(q[20:18]));
dpram_512x24_4096x3 buf7 (.wrclock(I_wclk),.wren(I_wren[7]),.wraddress(I_waddr),.data(I_wdata), .rdclock(rd_clk),.rden(rd_en),.rdaddress(rd_addr_7),.q(q[23:21]));
//***********************************************************
//rden_sr[4:0]
always@(posedge I_rclk)
    rden_sr <= {rden_sr[3:0],I_rden};

//rd_turn[2:0]
always@(posedge I_rclk)
    case(rden_sr[3:0])
        4'b0001:    rd_turn <= 3'd1;
        4'b0010:    rd_turn <= 3'd2;
        4'b0100:    rd_turn <= 3'd3;
        4'b1000:    rd_turn <= 3'd4;
        default:    rd_turn <= 3'd0;
    endcase

//rd_clk
//rd_en
assign rd_clk  = I_rclk;
assign rd_en   = |rden_sr[4:1];

// 为了满足时序，ad_x和rd_addr_x都寄存
// 那么延时就从原来的4变成了6
always@(posedge I_rclk)
    if(I_rden)
    begin
        ad_0  <= I_cfg_pt_offset_0 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_0 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_0 [8:0]);
        ad_1  <= I_cfg_pt_offset_1 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_1 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_1 [8:0]);
        ad_2  <= I_cfg_pt_offset_2 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_2 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_2 [8:0]);
        ad_3  <= I_cfg_pt_offset_3 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_3 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_3 [8:0]);
        ad_4  <= I_cfg_pt_offset_4 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_4 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_4 [8:0]);
        ad_5  <= I_cfg_pt_offset_5 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_5 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_5 [8:0]);
        ad_6  <= I_cfg_pt_offset_6 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_6 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_6 [8:0]);
        ad_7  <= I_cfg_pt_offset_7 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_7 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_7 [8:0]);
        ad_8  <= I_cfg_pt_offset_8 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_8 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_8 [8:0]);
        ad_9  <= I_cfg_pt_offset_9 [9] ? (I_raddr[8:0] + I_cfg_pt_offset_9 [8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_9 [8:0]);
        ad_10 <= I_cfg_pt_offset_10[9] ? (I_raddr[8:0] + I_cfg_pt_offset_10[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_10[8:0]);
        ad_11 <= I_cfg_pt_offset_11[9] ? (I_raddr[8:0] + I_cfg_pt_offset_11[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_11[8:0]);
        ad_12 <= I_cfg_pt_offset_12[9] ? (I_raddr[8:0] + I_cfg_pt_offset_12[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_12[8:0]);
        ad_13 <= I_cfg_pt_offset_13[9] ? (I_raddr[8:0] + I_cfg_pt_offset_13[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_13[8:0]);
        ad_14 <= I_cfg_pt_offset_14[9] ? (I_raddr[8:0] + I_cfg_pt_offset_14[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_14[8:0]);
        ad_15 <= I_cfg_pt_offset_15[9] ? (I_raddr[8:0] + I_cfg_pt_offset_15[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_15[8:0]);
        ad_16 <= I_cfg_pt_offset_16[9] ? (I_raddr[8:0] + I_cfg_pt_offset_16[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_16[8:0]);
        ad_17 <= I_cfg_pt_offset_17[9] ? (I_raddr[8:0] + I_cfg_pt_offset_17[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_17[8:0]);
        ad_18 <= I_cfg_pt_offset_18[9] ? (I_raddr[8:0] + I_cfg_pt_offset_18[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_18[8:0]);
        ad_19 <= I_cfg_pt_offset_19[9] ? (I_raddr[8:0] + I_cfg_pt_offset_19[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_19[8:0]);
        ad_20 <= I_cfg_pt_offset_20[9] ? (I_raddr[8:0] + I_cfg_pt_offset_20[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_20[8:0]);
        ad_21 <= I_cfg_pt_offset_21[9] ? (I_raddr[8:0] + I_cfg_pt_offset_21[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_21[8:0]);
        ad_22 <= I_cfg_pt_offset_22[9] ? (I_raddr[8:0] + I_cfg_pt_offset_22[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_22[8:0]);
        ad_23 <= I_cfg_pt_offset_23[9] ? (I_raddr[8:0] + I_cfg_pt_offset_23[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_23[8:0]);
        ad_24 <= I_cfg_pt_offset_24[9] ? (I_raddr[8:0] + I_cfg_pt_offset_24[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_24[8:0]);
        ad_25 <= I_cfg_pt_offset_25[9] ? (I_raddr[8:0] + I_cfg_pt_offset_25[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_25[8:0]);
        ad_26 <= I_cfg_pt_offset_26[9] ? (I_raddr[8:0] + I_cfg_pt_offset_26[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_26[8:0]);
        ad_27 <= I_cfg_pt_offset_27[9] ? (I_raddr[8:0] + I_cfg_pt_offset_27[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_27[8:0]);
        ad_28 <= I_cfg_pt_offset_28[9] ? (I_raddr[8:0] + I_cfg_pt_offset_28[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_28[8:0]);
        ad_29 <= I_cfg_pt_offset_29[9] ? (I_raddr[8:0] + I_cfg_pt_offset_29[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_29[8:0]);
        ad_30 <= I_cfg_pt_offset_30[9] ? (I_raddr[8:0] + I_cfg_pt_offset_30[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_30[8:0]);
        ad_31 <= I_cfg_pt_offset_31[9] ? (I_raddr[8:0] + I_cfg_pt_offset_31[8:0]) : (I_raddr[8:0] - I_cfg_pt_offset_31[8:0]);
    end

always@(posedge I_rclk)
    case(rden_sr[2:0])
        3'b001:
            begin
                rd_addr_0 <= {I_raddr[9],rd_turn[1:0],ad_0 [8:0]};
                rd_addr_1 <= {I_raddr[9],rd_turn[1:0],ad_4 [8:0]};
                rd_addr_2 <= {I_raddr[9],rd_turn[1:0],ad_8 [8:0]};
                rd_addr_3 <= {I_raddr[9],rd_turn[1:0],ad_12[8:0]};
                rd_addr_4 <= {I_raddr[9],rd_turn[1:0],ad_16[8:0]};
                rd_addr_5 <= {I_raddr[9],rd_turn[1:0],ad_20[8:0]};
                rd_addr_6 <= {I_raddr[9],rd_turn[1:0],ad_24[8:0]};
                rd_addr_7 <= {I_raddr[9],rd_turn[1:0],ad_28[8:0]};
            end                                                  
                                                                 
        3'b010:                                                 
            begin                                                
                rd_addr_0 <= {I_raddr[9],rd_turn[1:0],ad_1 [8:0]};
                rd_addr_1 <= {I_raddr[9],rd_turn[1:0],ad_5 [8:0]};
                rd_addr_2 <= {I_raddr[9],rd_turn[1:0],ad_9 [8:0]};
                rd_addr_3 <= {I_raddr[9],rd_turn[1:0],ad_13[8:0]};
                rd_addr_4 <= {I_raddr[9],rd_turn[1:0],ad_17[8:0]};
                rd_addr_5 <= {I_raddr[9],rd_turn[1:0],ad_21[8:0]};
                rd_addr_6 <= {I_raddr[9],rd_turn[1:0],ad_25[8:0]};
                rd_addr_7 <= {I_raddr[9],rd_turn[1:0],ad_29[8:0]};
            end                                                  
                                                                 
        3'b100:                                                 
            begin                                                
                rd_addr_0 <= {I_raddr[9],rd_turn[1:0],ad_2 [8:0]};
                rd_addr_1 <= {I_raddr[9],rd_turn[1:0],ad_6 [8:0]};
                rd_addr_2 <= {I_raddr[9],rd_turn[1:0],ad_10[8:0]};
                rd_addr_3 <= {I_raddr[9],rd_turn[1:0],ad_14[8:0]};
                rd_addr_4 <= {I_raddr[9],rd_turn[1:0],ad_18[8:0]};
                rd_addr_5 <= {I_raddr[9],rd_turn[1:0],ad_22[8:0]};
                rd_addr_6 <= {I_raddr[9],rd_turn[1:0],ad_26[8:0]};
                rd_addr_7 <= {I_raddr[9],rd_turn[1:0],ad_30[8:0]};
            end                                                  
                                                                 
        default:
            begin                                                
                rd_addr_0 <= {I_raddr[9],rd_turn[1:0],ad_3 [8:0]};
                rd_addr_1 <= {I_raddr[9],rd_turn[1:0],ad_7 [8:0]};
                rd_addr_2 <= {I_raddr[9],rd_turn[1:0],ad_11[8:0]};
                rd_addr_3 <= {I_raddr[9],rd_turn[1:0],ad_15[8:0]};
                rd_addr_4 <= {I_raddr[9],rd_turn[1:0],ad_19[8:0]};
                rd_addr_5 <= {I_raddr[9],rd_turn[1:0],ad_23[8:0]};
                rd_addr_6 <= {I_raddr[9],rd_turn[1:0],ad_27[8:0]};
                rd_addr_7 <= {I_raddr[9],rd_turn[1:0],ad_31[8:0]};
            end
    endcase
//***********************************************************
//q_tmp[DW-1:0]
genvar i;
generate
    for(i=0;i<M;i=i+1)
    begin: gen_q_tmp
        always@(posedge I_rclk)
        case(rd_turn[2:0])
            3'd2:   q_tmp[i*12+2+0 : i*12+0] <= q[i*3+2 : i*3];
            3'd3:   q_tmp[i*12+2+3 : i*12+3] <= q[i*3+2 : i*3];
            3'd4:   q_tmp[i*12+2+6 : i*12+6] <= q[i*3+2 : i*3];
            default:q_tmp[i*12+2+9 : i*12+9] <= q[i*3+2 : i*3]; // 可以删掉
        endcase
    end
endgenerate

//O_rdata[DW-1:0]
generate
    for(i=0;i<M;i=i+1)
    begin: gen_O_rdata
        assign O_rdata[i*12+8  : i*12+0] = q_tmp[i*12+8 : i*12];
        assign O_rdata[i*12+11 : i*12+9] = q[i*3+2 : i*3];
    end
endgenerate
//***********************************************************
endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
